﻿using System;
using System.Collections.Generic;
using System.Text;
using RollBackLib.src.utils;
using log4net;

namespace RollBackLib.src.core
{
    /// <summary>
    /// Encapsulates Scheduling of the BackupJob
    /// </summary>
    /// 
    [Serializable()]
    public class JobSchedule
    {
        private static ILog log = LogManager.GetLogger(typeof(JobSchedule));

        public bool m_Modified;

        private int m_howOften;
        public int m_HowOften
        {
            get { return m_howOften; }
            set
            {
                m_Modified = true;
                m_howOften = value;
            }
        }

        private int m_whatTimeOfDay;
        public int m_WhatTimeOfDay
        {
            get { return m_whatTimeOfDay; }
            set
            {
                m_Modified = true;
                m_whatTimeOfDay = value;
            }
        }

        private int m_whatDayOfWeek;
        public int m_WhatDayOfWeek
        {
            get { return m_whatDayOfWeek; }
            set
            {
                m_Modified = true;
                m_whatDayOfWeek = value;
            }
        }

        private int m_whatDate;
        public int m_WhatDate
        {
            get { return m_whatDate; }
            set
            {
                m_Modified = true;
                m_whatDate = value;
            }
        }

        private bool m_enabled;
        public bool m_Enabled
        {
            get { return m_enabled; }
            set
            {
                m_Modified = true;
                m_enabled = value;
            }
        }

        public JobSchedule()
        {
            m_HowOften = 0;
            m_WhatTimeOfDay = 3;
            m_Enabled = false;
            validateSchedule();
        }

        /// <summary>
        /// Validate this job schedule
        /// </summary>
        public void validateSchedule()
        {
            int howOften = m_howOften;
            int timeOfDay = m_whatTimeOfDay;
            int timeOfWeek = m_whatDayOfWeek;
            int date = m_whatDate;
            validateSchedule(ref howOften, ref timeOfDay, ref timeOfWeek, ref date);
            m_HowOften = howOften;
            m_WhatTimeOfDay = timeOfDay;
            m_WhatDayOfWeek = timeOfWeek;
            m_WhatDate = date;
            /*
            JobSchedule.validateSchedule(ref m_HowOften, 
                ref m_WhatTimeOfDay, 
                ref m_WhatDayOfWeek, 
                ref m_WhatDate);
             */
        }

        /// <summary>
        /// returns as parameter the valid values of the schedule according the values of the member
        /// </summary>
        /// <param name="howOften"></param>
        /// <param name="whatTimeOfDay"></param>
        /// <param name="whatDayOfWeek"></param>
        /// <param name="whatDate"></param>
        public static void validateSchedule(ref int howOften,
            ref int whatTimeOfDay,
            ref int whatDayOfWeek,
            ref int whatDate)
        {
            if(howOften <0 || howOften>=Scheduler.m_howOftenList.Length)
            {
                log.Warn("Invalid value for 'howOften' " + howOften + ", reseting to 0");
                howOften = 0;
            }

            if (whatTimeOfDay < 0 || whatTimeOfDay >= Scheduler.m_whatTimeOfDayList.Length)
            {
                whatTimeOfDay = 3;
            }
            switch (howOften)
            {
                case 0: // DAILY
                    {
                        // this means the run is Daily hence the only thing that makes sense is
                        // what time of the day to run
                        whatDate = -1;
                        whatDayOfWeek = -1;
                        break;
                    }
                case 1: // WEEKLY
                    {
                        // running weekly hence whatDate is null
                        whatDate = -1;
                        break;
                    }
                case 2: // MONTHLY
                    {
                        // running monthly hence what day of the week is null
                        whatDayOfWeek = -1;
                        break;
                    }
            }
        }

        public bool timeToSchedule(DateTime lastRun)
        {
            bool itsTime = false;
            DateTime now = DateTime.Now;
            int hour = 0;
            Scheduler.toTimeOfDay(m_WhatTimeOfDay,ref hour);
            
            //if (/*now.Hour >= hour &&*/ now.Date >= lastRun.Date)
            {
                switch (m_HowOften)
                {
                    case 0: // DAILY
                        {
                            if (now.Hour == hour) 
                            {
                                bool alreadyRunToday =
                                    (lastRun.Year == now.Year) && (lastRun.DayOfYear == now.DayOfYear) && (lastRun.Hour == hour);
                                if (!alreadyRunToday)
                                {
                                    itsTime = true;
                                }
                            }
                            break;
                        }
                    case 1: // WEEKLY
                        {
                            if ((now.DayOfWeek >= (DayOfWeek)m_WhatDayOfWeek) &&
                                (now.Day > lastRun.Day))
                            {
                                itsTime = true;
                            }
                            break;
                        }
                    case 2: // MONTHLY
                        {
                            int maxDaysThisMonth = DateTime.DaysInMonth(now.Year,now.Month);
                            if ((now.Day > lastRun.Day) && (m_WhatDate >= maxDaysThisMonth || now.Day >= m_WhatDate))
                            {
                                itsTime = true;
                            }
                            break;
                        }
                }
            }
            return itsTime;
        }

        public string getScheduleString()
        {
            string str = "Not Scheduled";
            int hour = 0;
            Scheduler.toTimeOfDay(m_WhatTimeOfDay,ref hour);

            if (m_Enabled)
            {

                switch (m_HowOften)
                {
                    case 0:
                        {
                            str = Scheduler.m_howOftenList[0] + " at " + Scheduler.m_whatTimeOfDayList[m_WhatTimeOfDay];
                        }
                        break;
                    case 1:
                        {
                            str = Scheduler.m_howOftenList[1] + " at " + Scheduler.m_whatTimeOfDayList[m_WhatTimeOfDay] + " on " + Scheduler.m_whatDayOfWeekList[m_WhatDayOfWeek];
                        }
                        break;
                    case 2:
                        {
                            str = Scheduler.m_howOftenList[2] + " at " + Scheduler.m_whatTimeOfDayList[m_WhatTimeOfDay] + " on day " + Scheduler.m_whatDateList[m_WhatDate];
                        }
                        break;
                }
            }
            return str;
        }

    }
}
